package com.virtual.repository.common.model;

import java.io.Serializable;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.virtual.repository.common.model.adapters.CollectionMapAdapter;
import com.virtual.repository.common.model.adapters.ModelConfigUnmarshallListener;
import com.virtual.repository.common.model.adapters.PropertyMapAdapter;

/**
 * Class representing the <strong>mapping</strong> element from configuration file.
 * It stores information about <code>Object</code> mapping between Java and source database.
 * 
 * @author kchaber
 */
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "mapping")
public class Mapping implements Serializable {
	private static final long serialVersionUID = 1850979530847707820L;
	
	/**
	 * The unique identifier used in referencing to this object.
	 */
	@XmlAttribute
	@XmlID
	private String id;
	
	/**
	 * The fully qualified class name of the Java <code>Object</code>.
	 */
	@XmlAttribute(name = "class")
	private String className;
	
	/**
	 * The <code>DataSource</code> object. Indicates the database where the mapped object will be stored.
	 */
	@XmlIDREF
	@XmlAttribute(name = "data-source")
	private DataSource dataSource;
	
	/**
	 * The name of the entity in the source database, which represents the mapped object. 
	 */
	@XmlAttribute(name = "db-entity-name")
	private String dbEntityName;
	
	/**
	 * The list of the mapped object's properties (internal fields). 
	 * Indexed by class's field name and also by the name in the entity/table.
	 */
	@XmlElement(name = "properties")
	@XmlJavaTypeAdapter(PropertyMapAdapter.class)
	private Map<String, Property> properties;
	
	/**
	 * The list of the object's collections (internal fields' collections).
	 * Indexed by the fully qualified class name of the single element of the collection.
	 */
	@XmlElement(name = "collections")
	@XmlJavaTypeAdapter(CollectionMapAdapter.class)
	private Map<String, CollectionProperty> collections;
	
	/**
	 * Field representing the identifier property - loaded in the {@link ModelConfigUnmarshallListener}
	 */
	private Property identifierProperty;
	
	/**
	 * The map of foreign keys properties - loaded in the {@link ModelConfigUnmarshallListener}
	 */
	private Map<String, Property> foreignKeys;
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public String getDbEntityName() {
		return dbEntityName;
	}

	public void setDbEntityName(String dbEntityName) {
		this.dbEntityName = dbEntityName;
	}

	public Map<String, Property> getProperties() {
		return properties;
	}
	
	public Property getProperty(String name) {
		return this.properties.get(name);
	}

	public void setProperties(Map<String, Property> properties) {
		this.properties = properties;
	}

	public Map<String, CollectionProperty> getCollections() {
		return collections;
	}
	
	public CollectionProperty getCollectionProperty(String name) {
		return this.collections.get(name);
	}

	public void setCollections(Map<String, CollectionProperty> collections) {
		this.collections = collections;
	}

	public void setIdentifierProperty(Property identifierProperty) {
		this.identifierProperty = identifierProperty;
	}
	
	public Property getIdentifierProperty() {
		return this.identifierProperty;
	}

	public Map<String, Property> getForeignKeys() {
		return foreignKeys;
	}
	
	public void setForeignKeys(Map<String, Property> foreignKeys) {
		this.foreignKeys = foreignKeys;
	}
	
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Mapping [id=");
		builder.append(id);
		builder.append(", className=");
		builder.append(className);
		builder.append(", dataSource=");
		builder.append(dataSource);
		builder.append(", dbEntityName=");
		builder.append(dbEntityName);
		builder.append(", properties=");
		builder.append(properties);
		builder.append(", identifierProperty=");
		builder.append(identifierProperty);
		builder.append(", collections=");
		builder.append(collections);
		builder.append("]");
		return builder.toString();
	}
}
